package com.jzsk.variable.center.service.jar;

import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jzsk.variable.center.common.base.ServiceException;
import com.jzsk.variable.center.common.utils.DateUtils;
import com.jzsk.variable.center.common.utils.buildjar.ClassInfo;
import com.jzsk.variable.center.common.utils.buildjar.ClassUtil;
import com.jzsk.variable.center.common.utils.buildjar.JarUtils;
import com.jzsk.variable.center.common.utils.buildjar.JavaCompilerInfo;
import com.jzsk.variable.center.dao.zhengxin.entity.ZxFieldsConfig;
import com.jzsk.variable.center.dao.zhengxin.entity.ZxJarConfig;
import com.jzsk.variable.center.dao.zhengxin.entity.ZxJarFieldsConfig;
import com.jzsk.variable.center.dao.zhengxin.mapper.ZxFieldsConfigMapper;
import com.jzsk.variable.center.dao.zhengxin.mapper.ZxJarConfigMapper;
import com.jzsk.variable.center.dao.zhengxin.mapper.ZxJarFieldsConfigMapper;
import com.jzsk.variable.center.domain.dto.jar.ExportJarReqDTO;
import com.jzsk.variable.center.domain.enums.FieldTypeEnum;
import com.jzsk.variable.center.domain.enums.NeedJarEnum;
import com.jzsk.variable.center.domain.enums.StatusCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
public class JarServiceImpl implements JarService {

    @Resource
    ZxJarConfigMapper zxJarConfigMapper;

    @Resource
    ZxJarFieldsConfigMapper zxJarFieldsConfigMapper;

    @Resource
    ZxFieldsConfigMapper zxFieldsConfigMapper;

    @Override
    public void exportJar(ExportJarReqDTO exportJarReqDTO, HttpServletResponse response) {
        //查询jar包配置
        ZxJarConfig zxJarConfig = zxJarConfigMapper.selectById(exportJarReqDTO.getJarConfigId());
        if (zxJarConfig == null) {
            throw new ServiceException(StatusCodeEnum.征信jar包配置不存在);
        }
        //查询jar包关联的征信字段（直取+加工）
        List<ZxJarFieldsConfig> zxJarFieldsConfigs = zxJarFieldsConfigMapper.selectList(Wrappers.lambdaQuery(new ZxJarFieldsConfig())
                .eq(ZxJarFieldsConfig::getJarId, zxJarConfig.getId()));
        zxJarFieldsConfigs.sort(Comparator.comparingInt(ZxJarFieldsConfig::getPriority));

        //查询直取字段配置
        List<String> fieldCodes = zxJarFieldsConfigs.stream()
                .filter(p -> p.getFieldType() == FieldTypeEnum.直取字段.getType())
                .map(ZxJarFieldsConfig::getFieldCode)
                .collect(Collectors.toList());
        List<ZxFieldsConfig> zxFieldsConfigs = zxFieldsConfigMapper.selectList(Wrappers.lambdaQuery(new ZxFieldsConfig())
                .select(ZxFieldsConfig::getId, ZxFieldsConfig::getDataType, ZxFieldsConfig::getImplement)
                .in(ZxFieldsConfig::getFieldCode, fieldCodes));
        List<String> impls = zxFieldsConfigs.stream()
                .map(input -> input.getImplement().substring(input.getImplement().lastIndexOf(".") + 1))
                .collect(Collectors.toList());

        String jarName = zxJarConfig.getJarName();
        String time = DateUtils.formatDateTime(LocalDateTime.now(), "yyyyMMddHHmmss");
        String finalJarName = jarName + time + ".jar";

        //获取zxtzys包下的所有class文件
        List<ClassInfo> allClassFiles = ClassUtil.getAllClasses("com.jzsk.variable.center.zhengxin.zxtzys");
        allClassFiles = allClassFiles.stream().filter(input -> {
            File clazz = input.getClazz();
            if (!clazz.getName().startsWith("FeatureR")) {
                return true;
            } else {
                //过滤掉不在jar包配置中的直取特征
                String pureName = clazz.getName().substring(clazz.getName().lastIndexOf("/") + 1)
                        .replace(".class", "");
                return impls.contains(pureName);
            }
        }).collect(Collectors.toList());

        //添加加工类变量

        List<ZxJarFieldsConfig> jarFieldsConfigs = zxJarFieldsConfigs.stream()
                .filter(p -> p.getFieldType() == FieldTypeEnum.加工字段.getType())
                .collect(Collectors.toList());
        List<JavaCompilerInfo> compileList = new ArrayList<>();
        for (ZxJarFieldsConfig fieldsConfig : jarFieldsConfigs) {
            JavaCompilerInfo javaCompilerInfo = new JavaCompilerInfo();
            javaCompilerInfo.setJavaStr(fieldsConfig.getScript());
            //正则匹配取类名
            Pattern pattern = Pattern.compile("class ([a-zA-Z0-9]+) implements");
            Matcher matcher = pattern.matcher(fieldsConfig.getScript());
            String className = matcher.group(1);
            javaCompilerInfo.setFullPathClassName("com.jzsk.variable.center.zhengxin.zxtzys.rules." + className);
            compileList.add(javaCompilerInfo);
        }
        Set<String> jarNameSet = new HashSet<>();
        NeedJarEnum[] values = NeedJarEnum.values();
        for (NeedJarEnum needJar : values) {
            jarNameSet.add(needJar.getJarName() + "-" + needJar.getVersion() + ".jar");
        }
        try {
            ByteArrayOutputStream error = JarUtils.compileFile(compileList, jarNameSet);
            if (error != null) {
                System.out.println(error.toString(StandardCharsets.UTF_8.name()));
            }
        } catch (Exception e) {
            log.error("动态编译文件异常", e);
            throw new ServiceException(StatusCodeEnum.动态编译文件异常);
        }

        try {
            //复制对应的class文件，到目标待打包目录
            JarUtils.copyClassToCompile(allClassFiles);
            String jarPath = "/data/log/rms-variable-center-zhengxin/" + finalJarName;
            //生成jar包
            JarUtils.buildJar(jarPath);

            //下载jar包
            File jarFile = new File(jarPath);
            OutputStream os = response.getOutputStream();
            response.setContentType("application/octet-stream");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(finalJarName, "UTF-8"));
            byte[] bytes = Files.readAllBytes(jarFile.toPath());
            os.write(bytes);
            os.flush();
            IoUtil.close(os);
        } catch (Exception e) {
            log.error("jar包生成失败", e);
            throw new ServiceException(StatusCodeEnum.征信jar导出失败);
        }
    }


}
